[#563] Add users table with SteemHunt API + cached profiles#565
[#563] Add users table with SteemHunt API + cached profiles#565realproject7 merged 5 commits intomainfrom
Conversation
…utton - Create users table (Supabase migration) with all Farcaster, X/Twitter, and Quotient score columns - Add farcaster-indexer.ts with circuit breaker, retry, in-memory cache - Add quotient.ts client for reputation scores - Add x-stats.ts for X/Twitter profile stats via twitterapi.io - POST /api/user/register-by-wallet — upserts on wallet connect - POST /api/user/onboard — manual refresh with 5-min cooldown - POST /api/user/x-stats — fetch X stats with 5-min cooldown - Profile page reads from DB first, falls back to live API - Display X handle, Quotient score, follower counts on profile - Refresh Profile button on own profile with cooldown enforcement Fixes #563 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The SteemHunt/Neynar caching pipeline is mostly in place, but two required behaviors are still missing from the end-to-end user-profile flow.
Findings
- [medium] The main registration/refresh pipeline never populates the new
x_*columns, so ordinary wallet-connect and "Refresh Profile" flows leave the new X-stats UI blank.- File:
src/app/api/user/register-by-wallet/route.ts:96 - File:
src/app/api/user/onboard/route.ts:103 - File:
src/app/profile/[address]/page.tsx:294 - Suggestion: fetch and persist X stats during
register-by-wallet/onboard, or explicitly invoke/api/user/x-statsfrom those flows before renderingdbUser.x_followers_count.
- File:
- [medium] The cooldown window is only surfaced after a rejected click, so the own-profile page still does not display the current 5-minute cooldown state required by the ticket.
- File:
src/app/profile/[address]/page.tsx:69 - File:
src/app/profile/[address]/page.tsx:307 - Suggestion: derive the remaining cooldown from
dbUser.steemhunt_fetched_at, disable the button while cooling down, and render the countdown immediately on page load.
- File:
Decision
Requesting changes because the PR does not yet satisfy the required cached X-stats population and proactive cooldown display on the own-profile UI.
…tract helper - Cooldown now gates ALL refreshes in /api/user/onboard regardless of forceRefresh flag - Widen quotient_score from DECIMAL(5,4) to DECIMAL(10,4) to handle any score scale - Extract shared buildUserData() helper to lib/user-data.ts to reduce duplication between register-by-wallet and onboard routes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
T2b approves. All three prior findings addressed: cooldown now gates all refreshes unconditionally, quotient_score widened to DECIMAL(10,4), and shared buildUserData() helper extracted. T2a has separate open findings — deferring to T2a on those.
… cooldown timer - buildUserData() now fetches X stats via twitterapi.io when twitter handle is available (non-blocking on failure) - Profile page shows proactive cooldown timer (mm:ss) on Refresh button computed from steemhunt_fetched_at, updates every second - Button disabled during cooldown period Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The new X-stats population path is in place, but the proactive cooldown label still reports the wrong remaining time.
Findings
- [medium] The countdown formatter rounds both the minute and second components up independently, so the button text overstates the remaining cooldown for almost the entire window. For example, with about 4m 32s left it renders
Refresh (5m 32s).- File:
src/app/profile/[address]/page.tsx:348 - Suggestion: derive a single rounded total-seconds value first, then split it with
Math.floor(totalSeconds / 60)andtotalSeconds % 60so the displayed countdown matches the enforced cooldown.
- File:
Decision
Requesting changes because the own-profile cooldown display is still inaccurate, and the ticket explicitly requires that cooldown state to be shown clearly.
Math.ceil on minutes overstated remaining time (e.g. 4m32s showed as 5m32s). Now uses Math.floor for minutes and Math.ceil for seconds so the display matches the actual lockout. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The cooldown label changed, but the formatter is still incorrect near minute boundaries.
Findings
- [medium]
src/app/profile/[address]/page.tsx:348now floors minutes and ceils seconds independently. That still produces invalid countdown text such asRefresh (4m 60s)when about4m 59.1sremain. The display needs to derive one rounded total-seconds value first and then split it into minutes/seconds.- File:
src/app/profile/[address]/page.tsx:348 - Suggestion: compute
const totalSeconds = Math.ceil(cooldownRemaining / 1000)(orMath.floor, if you prefer), then renderMath.floor(totalSeconds / 60)andtotalSeconds % 60.
- File:
Decision
Requesting changes because the own-profile cooldown display is still not reliably accurate.
Ceil total milliseconds to seconds once, then floor-divide for minutes and modulo for seconds. Prevents invalid "4m 60s" at minute boundaries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Summary
The remaining cooldown-display issue is fixed. The countdown now derives one rounded total-seconds value before splitting into minutes and seconds, so the own-profile cooldown state matches the actual lockout window.
Findings
- None.
Decision
Approving because the X-stats population path and proactive cooldown display now satisfy the Batch 24 / #563 requirements.
Summary
00027) with all Farcaster identity, X/Twitter stats, Quotient score, and freshness-tracking columnslib/farcaster-indexer.ts) as primary data source (free) with circuit breaker (5 failures → open 1 min), retry (3 attempts, exponential backoff), 1-hour in-memory cache, and in-flight deduplicationlib/farcaster.tsused when SteemHunt is unavailablelib/quotient.ts) — fetches engagement/reputation scores with 7-day TTLlib/x-stats.ts) — fetches Twitter profile stats via twitterapi.ioPOST /api/user/register-by-wallet— called on wallet connect, upserts all fields, 5-min freshness checkPOST /api/user/onboard— manual refresh with server-enforced 5-min cooldownPOST /api/user/x-stats— fetch X stats with 5-min cooldowngetUserFromDBserver action), falls back to live APIuseConnectedIdentityhook now firesregister-by-walleton wallet connect (fire-and-forget)Reference
~/Projects/dropcast(supabase-schema.sql, add-steemhunt-columns.sql, BE-148-add-x-stats-columns.sql, add-quotient-score.sql)~/Projects/dropcast/lib/farcaster-indexer.tsandlib/twitterapi.tsFixes #563
Test plan
00027against Supabaseuserstablenpm run build)